import datetime
import os
import time
import traceback

import requests
from loguru import logger
import hashlib
import random
import base64
import numpy
import json


class Wei_Meng:
    def __init__(self, playwright, host, app_id):
        self.app_id = app_id
        self.secret = "P4I8HCOP1OP7432XZVKR2MPJKKVQ7J"
        self.playwright = playwright
        self.host = host
        self.context = None
        self.browser = None
        self.page = None
        self.index_url = "https://account.weimob.com/login.html"
        self.trade_download_path = os.path.join(os.getcwd(), 'trade')
        self.tj_account = self.get_tujian_account()
        if not os.path.exists(self.trade_download_path):
            os.makedirs(self.trade_download_path)

    def login(self, store):
        browser = self.playwright.chromium.launch(headless=False)
        self.context = browser.new_context(accept_downloads=True)
        self.page = self.context.new_page()
        self.page.goto(self.index_url, timeout=20000)
        self.page.query_selector('span:has-text("密码登录")').click()
        time.sleep(1)
        self.page.query_selector('#loginForm_phone').fill(store['userName'])
        self.page.query_selector('#loginForm_password').fill(store['pwd'])
        time.sleep(1)
        self.page.query_selector('label.ant-checkbox-wrapper').click(timeout=3000)
        logger.info('点击登录...')
        self.page.query_selector('button[type="submit"]').click()
        time.sleep(5)
        try:
            self.page.query_selector('#loginForm_phone').fill(store['userName'])
            self.page.query_selector('#loginForm_password').fill(store['pwd'])
            time.sleep(1)
            self.page.query_selector('label.ant-checkbox-wrapper').click(timeout=3000)
            logger.info('点击登录...')
            self.page.query_selector('button[type="submit"]').click()
            time.sleep(5)
        except:
            pass
        self.check_slide_code()
        self.wait_for_loading(self.page, 'a[title="财务概况"]:visible')
        logger.info('登录成功')

    # 检查有无滑动验证码
    def check_slide_code(self):
        has_code = False
        login_frame = None
        for k in range(10):
            try:
                self.page.query_selector('div')
                login_frame = self.page.frame(url='https://turing.captcha.qcloud.com/cap_union_new_show?*')
                if login_frame is not None:
                    logger.info("出现滑动验证码...")
                    has_code = True
                    break
                time.sleep(1)
            except:
                logger.info(traceback.format_exc())
        if not has_code:
            return
        if login_frame.query_selector('#tcWrap:visible') is not None:
            logger.info("出现滑动验证码，开始滑动...")
            code_path = os.path.join(os.getcwd(), 'code.png')
            for k in range(20):
                try:
                    if login_frame.query_selector('#tcWrap:visible') is None:
                        break
                    login_frame.query_selector('#reload').click()
                    time.sleep(2)
                    login_frame.query_selector('#slideBg').screenshot(path=code_path)
                    time.sleep(0.5)
                    dist = int(self.get_slider_xy(code_path))
                    box = login_frame.query_selector('#tcaptcha_drag_thumb').bounding_box()
                    track = self.get_tracks(dist - 20, 1, self.ease_out_quart)
                    ix = int(box['x'] + box['width'] // 2)
                    iy = int(box['y'] + box['height'] // 2)
                    self.page.mouse.move(ix, iy)
                    self.page.mouse.down(button='left')
                    self.move_to_gap(self.page, ix, iy, track)
                    time.sleep(1.5)
                    logger.info("滑动完成...")
                    time.sleep(5)
                except:
                    pass

    def ease_out_quart(self, x):
        return 1 - pow(1 - x, 4)

    def get_tracks(self, distance, seconds, ease_func):
        distance += 0
        tracks = [0]
        offsets = [0]
        for t in numpy.arange(0.0, seconds, 0.1):
            ease = ease_func
            offset = round(ease(t / seconds) * distance)
            tracks.append(offset - offsets[-1])
            offsets.append(offset)
        tracks.extend([-3, -2, -3, -2, -2, -2, -2, -1, -0, -1, -1, -1])
        return tracks

    def move_to_gap(self, page, ix, iy, track):
        """
        慢速移动鼠标
        :param ix:
        :param iy:
        :param track:
        :return:
        """
        f_y = [10, 12, 4, 6, 8, -4, -6, -8]
        mx = ix
        while track:
            x = track.pop(0)
            mx = mx + x
            page.mouse.move(mx, iy + random.choice(f_y))
            time.sleep(0.1)
        time.sleep(1)
        page.mouse.up()

    def get_slider_xy(self, backImgPath):
        api = 'http://api.ttshitu.com/base64'
        with open(backImgPath, 'rb') as f:
            base64_data = base64.b64encode(f.read())
            b642 = base64_data.decode()
        params = {"typeid": "33", "image": b642, "username": self.tj_account['tjName'], "password": self.tj_account['tjPass']}
        headers = {'content-type': 'application/json;charset=UTF-8'}
        result = json.loads(requests.post(api, json=params, headers=headers).text)
        if result['success']:
            return result["data"]["result"]
        else:
            logger.info(result["message"])
            return result["data"]

    def wait_for_loading(self, page, path):
        for i in range(20):
            try:
                if page.query_selector(path) is not None and page.query_selector(path).is_visible():
                    break
            except:
                pass
            time.sleep(1)
            logger.info(f'等待页面加载【{i+1}】秒...')

    def download_trade_detail(self, store, yesterday):
        logger.info('财务概况...')
        self.close_notice_dialog()
        self.page.query_selector('a[title="财务概况"]').click()
        self.wait_for_loading(self.page, 'div[role="tab"]:has-text("交易明细")')
        logger.info('点击交易明细...')
        self.page.query_selector('div[role="tab"]:has-text("交易明细")').click()
        self.wait_for_loading(self.page, 'input[data-name="orderNo"]')
        self.close_invoice_dialog()
        # 选择交易时间
        self.page.query_selector('input[placeholder="开始日期"]').click()
        time.sleep(1)
        self.page.query_selector('input[placeholder="开始日期"]').fill(yesterday)
        time.sleep(1)
        self.page.query_selector('input[placeholder="结束日期"]').click()
        time.sleep(1)
        self.page.query_selector('input[placeholder="结束日期"]').fill(yesterday)
        time.sleep(1)
        self.page.keyboard.press("Enter")
        time.sleep(1)
        logger.info('点击查询...')
        with self.page.expect_response('https://master.weimob.com/api3/finance/tradeDetail/list') as res:
            self.page.query_selector('button:has-text("查询")').click()
        response = res.value
        self.wait(self.page)
        if response.status:
            total = response.json()['data']['totalCount']
            if total == 0:
                logger.info('暂无数据')
                return None, yesterday
            logger.info(f'共查到【{total}】条数据')
            logger.info('点击导出...')
            self.page.query_selector('button:has-text("导出")').click()
            time.sleep(10)
            logger.info('点击更多报表...')
            with self.page.expect_popup() as popup_info:
                self.page.query_selector('a:has-text("更多报表")').click()
            new_page = popup_info.value
            self.wait(new_page)
            self.wait_for_loading(new_page, 'button:has-text("刷新")')
            tr_list = new_page.query_selector_all('div.klein-table >> table >> tbody >> tr.klein-table-row')
            tr_index = -1
            for index, tr in enumerate(tr_list):
                create_time = tr.query_selector('td >> nth=6').text_content()
                download_count = tr.query_selector('td >> nth=5').text_content()
                if str(create_time).startswith(datetime.datetime.now().strftime('%Y-%m-%d')) and int(download_count) == 0:
                    logger.info(f'找到报表创建时间：{create_time}，下载次数：{download_count}')
                    tr_index = index
                    tr_no = tr.query_selector('td >> nth=0').text_content()
                    break
            if tr_index >= 0:
                # 下载报表
                with new_page.expect_download() as download_info:
                    new_page.query_selector(f'div.klein-table >> table >> tbody >> tr.klein-table-row >> nth={tr_index} >> a:has-text("下载")').click()
                download_obj = download_info.value
                file_path = os.path.join(self.trade_download_path, f'wmTradeDetail-{store["platformStoreName"]}-{yesterday}-{datetime.datetime.now().strftime("%Y%m%d%H%M%S")}.xlsx')
                # 删除旧文件
                if os.path.exists(file_path):
                    os.remove(file_path)
                download_obj.save_as(file_path)
                # 等待文件下载完成
                for i in range(60):
                    if os.path.exists(file_path):
                        break
                    time.sleep(1)
                if not os.path.exists(file_path):
                    raise Exception(f"【{file_path}】下载失败")
                logger.info(f"【{file_path}】下载成功")
                new_page.close()
                return file_path
        else:
            raise Exception('查询超时')

    def get_trade_detail_count(self, period):
        logger.info('财务概况...')
        self.close_notice_dialog()
        self.page.query_selector('a[title="财务概况"]').click()
        self.wait_for_loading(self.page, 'div[role="tab"]:has-text("交易明细")')
        logger.info('点击交易明细...')
        self.page.query_selector('div[role="tab"]:has-text("交易明细")').click()
        self.wait_for_loading(self.page, 'input[data-name="orderNo"]')
        self.close_invoice_dialog()
        # 选择交易时间
        self.page.query_selector('input[placeholder="开始日期"]').click()
        time.sleep(1)
        start_date = period + '-01'
        self.page.query_selector('input[placeholder="开始日期"]').fill(start_date)
        time.sleep(1)
        self.page.query_selector('input[placeholder="结束日期"]').click()
        time.sleep(1)
        end_date = ((datetime.datetime.strptime(start_date, '%Y-%m-%d') + datetime.timedelta(days=31)).replace(day=1) - datetime.timedelta(days=1)).strftime('%Y-%m-%d')
        self.page.query_selector('input[placeholder="结束日期"]').fill(end_date)
        time.sleep(1)
        self.page.keyboard.press("Enter")
        time.sleep(1)
        logger.info('点击查询...')
        with self.page.expect_response('https://master.weimob.com/api3/finance/tradeDetail/list') as res:
            self.page.query_selector('button:has-text("查询")').click()
        response = res.value
        self.wait(self.page)
        if response.status:
            total = response.json()['data']['totalCount']
            return total
        else:
            raise Exception('查询失败')

    def close_invoice_dialog(self):
        for i in range(5):
            try:
                if self.page.query_selector('span.weimob-components-notification-noti-close:visible') is not None:
                    self.page.query_selector('span.weimob-components-notification-noti-close:visible').click()
                time.sleep(1)
            except:
                pass

    # 关闭到期通知弹窗
    def close_notice_dialog(self):
        for t in range(3):
            for i in range(3):
                try:
                    if self.page.query_selector('button.klein-modal-close:visible') is not None:
                        self.page.query_selector('button.klein-modal-close:visible').click(timeout=3000)
                    time.sleep(1)
                except:
                    logger.info(traceback.format_exc())
            for i in range(3):
                try:
                    if len(self.page.query_selector_all('button:has-text("我知道了"):visible')) > 0:
                        for btn in self.page.query_selector_all('button:has-text("我知道了"):visible'):
                            btn.click(timeout=3000)
                    time.sleep(1)
                except:
                    pass

    def get_store_account(self, platform, type):
        timestamp = int(time.time() * 1000)
        text = "{}{}{}".format(self.app_id, timestamp, self.secret)
        sign = hashlib.md5(text.encode(encoding='UTF-8')).hexdigest()
        url = self.host + f"api/v1/storeAccount/getAccountList/{platform}?appId={self.app_id}&type={type}&sign={sign.upper()}&timestamp={timestamp}"
        logger.info(url)
        res = requests.get(url)
        logger.info(f'获取店铺账号结果：{res.text}')
        if res.status_code == 200:
            return res.json()['data']

    # 获取图鉴账号密码
    def get_tujian_account(self):
        timestamp = int(time.time() * 1000)
        text = "{}{}{}".format(self.app_id, timestamp, self.secret)
        sign = hashlib.md5(text.encode(encoding='UTF-8')).hexdigest()
        url = self.host + f"api/v1/tjAccount/findOne?appId={self.app_id}&sign={sign.upper()}&timestamp={timestamp}"
        res = requests.get(url)
        if res.status_code == 200:
            return res.json()['data']
    def wait(self, page, seconds=1):
        try:
            page.wait_for_load_state(state="domcontentloaded")
            time.sleep(seconds)
        except:
            pass

    def close(self):
        try:
            if self.page:
                self.page.close()
        except:
            pass
        try:
            if self.browser:
                self.browser.close()
        except:
            pass
        try:
            if self.context:
                self.context.close()
        except:
            pass

    def upload_file(self, api_url, coding_param, file_list):
        try:
            timestamp = int(time.time() * 1000)
            text = "{}{}{}".format(self.app_id, timestamp, self.secret)
            sign = hashlib.md5(text.encode(encoding='UTF-8')).hexdigest()
            logger.info("正在上传文件到服务器")
            url = self.host + api_url + f"?appId={self.app_id}&sign={sign.upper()}&timestamp={timestamp}"
            files = []
            for file in file_list:
                files.append(('file', (open(file, 'rb'))))
            logger.info(f'上传文件到服务器url：{url}')
            response = requests.request("POST", url, files=files, headers={'codingParam': coding_param}, timeout=180)
            logger.info('上传文件到服务器结果：' + response.text)
        except:
            logger.info(traceback.format_exc())

    def encode_param(self, data_list):
        timestamp = int(time.time() * 1000)
        text = "{}{}{}".format(self.app_id, timestamp, self.secret)
        sign = hashlib.md5(text.encode(encoding='UTF-8')).hexdigest()
        url = self.host + f"api/v1/storeAccount/codingParams?appId={self.app_id}&sign={sign.upper()}&timestamp={timestamp}"
        res = requests.post(url, data=json.dumps(data_list), headers={'content-type': 'application/json'})
        if res.status_code == 200:
            return res.json()['data']